import { XAttribute, XFloatRowsInfo, XForm, XReport, XSheet } from "@/ts/base/schema";
import {cloneDeep} from "lodash";

function* range(start: number, end: number, step = 1) {
  for (let i = start; i <= end; i += step) {
    yield i;
  }
}

export function isReport(form: XForm | XReport): form is XReport {
  return form.typeName === '表格';
}


export function sheetToForm(sheet: XSheet, reportId: string) {
  const form = cloneDeep(sheet) as any as XForm;
  delete (form as any).sheets;

  form.id = sheet.attributeId!;
  form.attributes ||= [];
  form.rule ||= [];
  
  for (const [cell, config] of Object.entries(sheet.cells)) {
    let attr = {
      id: cell,
      code: cell,
      name: '单元格' + cell,
      propId: cell,
      formId: reportId,
      options: config
    } as any as XAttribute;
    form.attributes.push(attr);
  }
  
  return form;
}

export const coordToCell = (obj: { row: number; col: number }) => {
  const row = obj.row + 1;
  const col = obj.col + 1;

  function colNumToLetter(num: number): string {
    let letter = '';
    while (num > 0) {
      const temp = (num - 1) % 26;
      letter = String.fromCharCode(temp + 65) + letter;
      num = Math.floor((num - 1 - temp) / 26);
    }
    return letter || 'A';
  }
  const columnLetter = colNumToLetter(col);
  const cellReference = `${columnLetter}${row}`;
  return cellReference;
};

/** 解析坐标 */
export const cellToCoord = (str: any) => {
  let columnLetters = str.match(/[A-Z]+/)[0];
  let rowNumber = Number(str.match(/\d+/)[0]);
  let columnNumber = 0;
  for (let i = 0; i < columnLetters.length; i++) {
    columnNumber *= 26;
    columnNumber += columnLetters.charCodeAt(i) - 'A'.charCodeAt(0);
  }
  return { col: columnNumber, row: rowNumber - 1 };
};

/** 下标1开始的版本 */
export function coordToCell1Base(obj: { row: number; col: number }) {
  return coordToCell({
    col: obj.col - 1,
    row: obj.row - 1,
  });
}

/** 下标1开始的版本 */
export function cellToCoord1Base(cell: string) {
  let { col, row } = cellToCoord(cell);
  row++;
  col++;
  return { col, row };
}

const getColumnNumber = (colStr: any) => {
  let result = 0;
  for (let i = 0; i < colStr.length; i++) {
    result = result * 26 + (colStr.charCodeAt(i) - 'A'.charCodeAt(0) + 1);
  }
  return result;
};

/** 数字转字母 */
export const numberToLetters = (number: any) => {
  let result = '';
  while (number > 0) {
    number--; // 调整偏移
    let remainder = number % 26;
    let letter = String.fromCharCode(65 + remainder);
    result = letter + result;
    number = Math.floor(number / 26);
  }
  return result;
};

export const getRangeCells = (startCell: string, endCell: string) => {
  const { col: startColNum, row: startRowNum } = cellToCoord(startCell);
  const { col: endColNum, row: endRowNum } = cellToCoord(endCell);

  return Array.from(range(startRowNum, endRowNum)).flatMap((row) =>
    Array.from(range(startColNum, endColNum)).map((col) =>
      coordToCell({
        col,
        row,
      }),
    ),
  );
};

export const parseRanges = (ranges: string[]) => {
  const result: any[] = [];

  ranges.forEach((range) => {
    const [startCell, endCell] = range.split(':');
    const [startCol, startRow] = startCell.split('');
    const [endCol, endRow] = endCell.split('');
    const startColNum = getColumnNumber(startCol);
    const endColNum = getColumnNumber(endCol);
    const colspan = endColNum - startColNum + 1;
    const rowspan =
      parseInt(startRow, 10) === parseInt(endRow, 10)
        ? 1
        : Number(parseInt(endRow, 10)) - Number(parseInt(startRow, 10));
    result.push({
      row: Number(parseInt(startRow, 10)) - 1,
      col: startColNum - 1,
      rowspan: rowspan,
      colspan: colspan,
    });
  });

  return result;
};


function splitKey(str: string): { letter: string; number: number } | null {
  const matches = str.match(/[A-Z]+|[0-9]+/g);
  if (matches && matches.length === 2) {
    let letter = matches[0];
    if (str.includes('_')) {
      letter = letter + '_code';
    }
    const number = parseInt(matches[1], 10);
    return { letter, number };
  }
  return null;
}

export const getSubData = (setting: XFloatRowsInfo, data: any) => {
  const dataJson = data[setting.attributeId!] ?? {};
  const maxKeyNumber = Math.max(
    ...Object.keys(dataJson).map((key) => {
      const match = key.match(/\d+/);
      return match ? parseInt(match[0], 10) : 0;
    }),
    0,
  );

  const resultArrayLength = Math.ceil(maxKeyNumber / 10) * 10;
  let jsonTemplate: any = {};
  setting.rowsInfo.forEach((item: any) => {
    if (item.rule.value.type === '属性型') {
      jsonTemplate[item.name + '_code'] = undefined;
    }
    jsonTemplate[item.name] = undefined;
  });
  const resultArray = new Array(resultArrayLength)
    .fill(null)
    .map(() => ({ ...jsonTemplate }));

  Object.keys(dataJson).forEach((key) => {
    let value = dataJson[key];
    const result = splitKey(key);
    if (result) {
      const info = setting.rowsInfo.find((rowInfo) => rowInfo.name === result.letter);
      if (info?.valueType === '数字框' && typeof value === 'number') {
        const factor: number = Math.pow(10, info.accuracy ?? 2);
        value = Math.round((value || 0) * factor) / factor;
      }
      resultArray[result.number - 1][result.letter] = value;
    } else {
      console.warn(`Invalid key format: ${key}`);
    }
  });

  return resultArray;
};